// define this flag for COM
#include "stdafx.h"
#define _WIN32_DCOM
#include <windows.h>
#include <conio.h>
#include <objbase.h>
#include <rpcsal.h>
#include <objbase.h>
#include <msxml6.h>
#include <atlbase.h>
#include <iostream>
#include <iomanip>
// headers needed to use WLAN APIs 
#include <wlanapi.h>

using namespace std;
wchar_t szProfileStringFmt[] = 
	L"<?xml version=\"1.0\"?>\n"
	L"	<WLANProfile xmlns=\"http://www.microsoft.com/networking/WLAN/profile/v1\">\n"
	L"	<name>%S</name>\n"
	L"	<SSIDConfig>\n"
	L"		<SSID>\n"
	L"			<name>%S</name>\n"
	L"		</SSID>\n"
	L"		<nonBroadcast>false</nonBroadcast>\n"
	L"	</SSIDConfig>\n"
	L"	<connectionType>ESS</connectionType>\n"
	L"	<connectionMode>auto</connectionMode>\n"
	L"	<MSM>\n"
	L"		<security>\n"
	L"			<authEncryption>\n"
	L"				<authentication>open</authentication>\n"
	L"				<encryption>WEP</encryption>\n"
	L"				<useOneX>false</useOneX>\n"
	L"			</authEncryption>\n"
	L"			<sharedKey>\n"
	L"				<keyType>networkKey</keyType>\n"
	L"				<protected>false</protected>\n"
	L"				<keyMaterial>%S</keyMaterial>\n"
	L"			</sharedKey>\n"
	L"		</security>\n"
	L"	</MSM>\n"
	L"</WLANProfile>\n"
	;

// get win32 error from HRESULT
#define WIN32_FROM_HRESULT(hr)           \
	(SUCCEEDED(hr) ? ERROR_SUCCESS :    \
	(HRESULT_FACILITY(hr) == FACILITY_WIN32 ? HRESULT_CODE(hr) : (hr)))


//
// Utility functions
//

// get interface state string
LPWSTR
GetInterfaceStateString(
						__in WLAN_INTERFACE_STATE wlanInterfaceState
						)
{
	LPWSTR strRetCode;

	switch(wlanInterfaceState)
	{
	case wlan_interface_state_not_ready:
		strRetCode = L"\"not ready\"";
		break;
	case wlan_interface_state_connected:
		strRetCode = L"\"connected\"";
		break;
	case wlan_interface_state_ad_hoc_network_formed:
		strRetCode = L"\"ad hoc network formed\"";
		break;
	case wlan_interface_state_disconnecting:
		strRetCode = L"\"disconnecting\"";
		break;
	case wlan_interface_state_disconnected:
		strRetCode = L"\"disconnected\"";
		break;
	case wlan_interface_state_associating:
		strRetCode = L"\"associating\"";
		break;
	case wlan_interface_state_discovering:
		strRetCode = L"\"discovering\"";
		break;
	case wlan_interface_state_authenticating:
		strRetCode = L"\"authenticating\"";
		break;
	default:
		strRetCode = L"\"invalid interface state\"";
	}

	return strRetCode;
}

// get ACM notification string
LPWSTR
GetAcmNotificationString(
						 __in DWORD acmNotif
						 )
{
	LPWSTR strRetCode;

	switch(acmNotif)
	{
	case wlan_notification_acm_autoconf_enabled:
		strRetCode = L"\"autoconf enabled\"";
		break;
	case wlan_notification_acm_autoconf_disabled:
		strRetCode = L"\"autoconf disabled\"";
		break;
	case wlan_notification_acm_background_scan_enabled:
		strRetCode = L"\"background scan enabled\"";
		break;
	case wlan_notification_acm_background_scan_disabled:
		strRetCode = L"\"background scan disabled\"";
		break;
	case wlan_notification_acm_power_setting_change:
		strRetCode = L"\"power setting change\"";
		break;
	case wlan_notification_acm_scan_complete:
		strRetCode = L"\"scan complete\"";
		break;
	case wlan_notification_acm_scan_fail:
		strRetCode = L"\"scan fail\"";
		break;
	case wlan_notification_acm_connection_start:
		strRetCode = L"\"connection start\"";
		break;
	case wlan_notification_acm_connection_complete:
		strRetCode = L"\"connection complete\"";
		break;
	case wlan_notification_acm_connection_attempt_fail:
		strRetCode = L"\"connection fail\"";
		break;
	case wlan_notification_acm_filter_list_change:
		strRetCode = L"\"filter list change\"";
		break;
	case wlan_notification_acm_interface_arrival:
		strRetCode = L"\"interface arrival\"";
		break;
	case wlan_notification_acm_interface_removal:
		strRetCode = L"\"interface removal\"";
		break;
	case wlan_notification_acm_profile_change:
		strRetCode = L"\"profile change\"";
		break;
	case wlan_notification_acm_profiles_exhausted:
		strRetCode = L"\"profiles exhausted\"";
		break;
	case wlan_notification_acm_network_not_available:
		strRetCode = L"\"network not available\"";
		break;
	case wlan_notification_acm_network_available:
		strRetCode = L"\"network available\"";
		break;
	case wlan_notification_acm_disconnecting:
		strRetCode = L"\"disconnecting\"";
		break;
	case wlan_notification_acm_disconnected:
		strRetCode = L"\"disconnected\"";
		break;
	case wlan_notification_acm_adhoc_network_state_change:
		strRetCode = L"\"ad hoc network state changes\"";
		break;
	default:
		strRetCode = L"\"unknown ACM notification\"";
	}

	return strRetCode;
}

// get MSMM notification string
LPWSTR
GetMsmNotificationString(
						 __in DWORD msmNotif
						 )
{
	LPWSTR strRetCode;

	switch(msmNotif)
	{
	case wlan_notification_msm_associating:
		strRetCode = L"\"associating\"";
		break;
	case wlan_notification_msm_associated:
		strRetCode = L"\"associated\"";
		break;
	case wlan_notification_msm_authenticating:
		strRetCode = L"\"authenticating\"";
		break;
	case wlan_notification_msm_connected:
		strRetCode = L"\"connected\"";
		break;
	case wlan_notification_msm_roaming_start:
		strRetCode = L"\"roaming start\"";
		break;
	case wlan_notification_msm_roaming_end:
		strRetCode = L"\"roaming end\"";
		break;
	case wlan_notification_msm_radio_state_change:
		strRetCode = L"\"radio state change\"";
		break;
	case wlan_notification_msm_signal_quality_change:
		strRetCode = L"\"signal quality change\"";
		break;
	case wlan_notification_msm_disassociating:
		strRetCode = L"\"disassociating\"";
		break;
	case wlan_notification_msm_disconnected:
		strRetCode = L"\"disconnected\"";
		break;
	case wlan_notification_msm_peer_join:
		strRetCode = L"\"a peer joins the ad hoc network\"";
		break;
	case wlan_notification_msm_peer_leave:
		strRetCode = L"\"a peer leaves the ad hoc network\"";
		break;
	case wlan_notification_msm_adapter_removal:
		strRetCode = L"\"adapter is in a bad state\"";
		break;
	default:
		strRetCode = L"\"unknown MSM notification\"";
	}

	return strRetCode;
}

// get connection mode string
LPWSTR
GetConnectionModeString(
						__in WLAN_CONNECTION_MODE wlanConnMode
						)
{
	LPWSTR strRetCode;

	switch(wlanConnMode)
	{
	case wlan_connection_mode_profile:
		strRetCode = L"\"manual connection with a profile\"";
		break;
	case wlan_connection_mode_temporary_profile:
		strRetCode = L"\"manual connection with a temporary profile\"";
		break;
	case wlan_connection_mode_discovery_secure:
		strRetCode = L"\"connection to a secure network without a profile\"";
		break;
	case wlan_connection_mode_discovery_unsecure:
		strRetCode = L"\"connection to an unsecure network without a profile\"";
		break;
	case wlan_connection_mode_auto:
		strRetCode = L"\"automatic connection with a profile\"";
		break;
	default:
		strRetCode = L"\"invalid connection mode\"";
	}

	return strRetCode;
}

// get PHY type string
LPWSTR 
GetPhyTypeString(
				 __in ULONG uDot11PhyType
				 )
{
	LPWSTR strRetCode;

	switch(uDot11PhyType)
	{
	case dot11_phy_type_dsss:
		strRetCode = L"\"DSSS\"";
		break;
	case dot11_phy_type_erp:
		strRetCode = L"\"802.11g\"";
		break;
	case dot11_phy_type_fhss:
		strRetCode = L"\"FHSS\"";
		break;
	case dot11_phy_type_hrdsss:
		strRetCode = L"\"802.11b\"";
		break;
	case dot11_phy_type_irbaseband:
		strRetCode = L"\"IR-base band\"";
		break;
	case dot11_phy_type_ofdm:
		strRetCode = L"\"802.11a\"";
		break;
	case dot11_phy_type_any:
		strRetCode = L"\"any\"";
		break;
	default:
		strRetCode = L"\"Unknown PHY type\"";
	}

	return strRetCode;
}

// get BSS type string
LPWSTR 
GetBssTypeString(
				 __in DOT11_BSS_TYPE dot11BssType
				 )
{
	LPWSTR strRetCode;

	switch(dot11BssType)
	{
	case dot11_BSS_type_infrastructure:
		strRetCode = L"\"Infrastructure\"";
		break;
	case dot11_BSS_type_independent:
		strRetCode = L"\"Ad hoc\"";
		break;
	case dot11_BSS_type_any:
		strRetCode = L"\"Any\"";
		break;
	default:
		strRetCode = L"\"Unknown BSS type\"";
	}

	return strRetCode;
}

// get radio state string
LPWSTR
GetRadioStateString(
					__in DOT11_RADIO_STATE radioState
					)
{
	LPWSTR strRetCode;

	switch(radioState)
	{
	case dot11_radio_state_on:
		strRetCode = L"\"on\"";
		break;
	case dot11_radio_state_off:
		strRetCode = L"\"off\"";
		break;
	default:
		strRetCode = L"\"unknown state\"";
	}

	return strRetCode;
}


// get auth algorithm string
LPWSTR 
GetAuthAlgoString(
				  __in DOT11_AUTH_ALGORITHM dot11AuthAlgo
				  )
{
	LPWSTR strRetCode = L"\"Unknown algorithm\"";

	switch(dot11AuthAlgo)
	{
	case DOT11_AUTH_ALGO_80211_OPEN:
		strRetCode = L"\"Open\"";
		break;
	case DOT11_AUTH_ALGO_80211_SHARED_KEY:
		strRetCode = L"\"Shared\"";
		break;
	case DOT11_AUTH_ALGO_WPA:
		strRetCode = L"\"WPA-Enterprise\"";
		break;
	case DOT11_AUTH_ALGO_WPA_PSK:
		strRetCode = L"\"WPA-Personal\"";
		break;
	case DOT11_AUTH_ALGO_WPA_NONE:
		strRetCode = L"\"WPA-NONE\"";
		break;
	case DOT11_AUTH_ALGO_RSNA:
		strRetCode = L"\"WPA2-Enterprise\"";
		break;
	case DOT11_AUTH_ALGO_RSNA_PSK:
		strRetCode = L"\"WPA2-Personal\"";
		break;
	default:
		if (dot11AuthAlgo & DOT11_AUTH_ALGO_IHV_START)
		{
			strRetCode = L"\"Vendor-specific algorithm\"";
		}
	}

	return strRetCode;
}

// get cipher algorithm string
LPWSTR 
GetCipherAlgoString(
					__in DOT11_CIPHER_ALGORITHM dot11CipherAlgo
					)
{
	LPWSTR strRetCode = L"\"Unknown algorithm\"";

	switch(dot11CipherAlgo)
	{
	case DOT11_CIPHER_ALGO_NONE:
		strRetCode = L"\"None\"";
		break;
	case DOT11_CIPHER_ALGO_WEP40:
		strRetCode = L"\"WEP40\"";
		break;
	case DOT11_CIPHER_ALGO_TKIP:
		strRetCode = L"\"TKIP\"";
		break;
	case DOT11_CIPHER_ALGO_CCMP:
		strRetCode = L"\"AES\"";
		break;
	case DOT11_CIPHER_ALGO_WEP104:
		strRetCode = L"\"WEP104\"";
		break;
	case DOT11_CIPHER_ALGO_WPA_USE_GROUP:
		strRetCode = L"\"USE-GROUP\"";
		break;
	case DOT11_CIPHER_ALGO_WEP:
		strRetCode = L"\"WEP\"";
		break;
	default:
		if (dot11CipherAlgo & DOT11_CIPHER_ALGO_IHV_START)
		{
			strRetCode = L"\"Vendor-specific algorithm\"";
		}
	}

	return strRetCode;
}

// get SSID from the WCHAR string
DWORD
StringWToSsid(
			  __in LPCWSTR strSsid, 
			  __out PDOT11_SSID pSsid
			  )
{
	DWORD dwRetCode = ERROR_SUCCESS;
	BYTE pbSsid[DOT11_SSID_MAX_LENGTH + 1] = {0};

	if (strSsid == NULL || pSsid == NULL)
	{
		dwRetCode = ERROR_INVALID_PARAMETER;
	}
	else
	{
		pSsid->uSSIDLength = WideCharToMultiByte (CP_ACP,
			0,
			strSsid,
			-1,
			(LPSTR)pbSsid,
			sizeof(pbSsid),
			NULL,
			NULL);

		pSsid->uSSIDLength--;
		memcpy(&pSsid->ucSSID, pbSsid, pSsid->uSSIDLength);
	}

	return dwRetCode;
}

// copy SSID to a null-terminated WCHAR string
// count is the number of WCHAR in the buffer.
LPWSTR
SsidToStringW(
			  __out_ecount(count) LPWSTR   buf,
			  __in ULONG   count,
			  __in PDOT11_SSID pSsid
			  )
{
	ULONG   bytes, i;

	bytes = min( count-1, pSsid->uSSIDLength);
	for( i=0; i<bytes; i++)
		mbtowc( &buf[i], (const char *)&pSsid->ucSSID[i], 1);
	buf[bytes] = '\0';

	return buf;
}


// the max lenght of the reason string in characters
#define WLSAMPLE_REASON_STRING_LEN 256

// print the reason string
VOID
PrintReason(
			__in WLAN_REASON_CODE reason
			)
{
	WCHAR strReason[WLSAMPLE_REASON_STRING_LEN];

	if (WlanReasonCodeToString(
		reason, 
		WLSAMPLE_REASON_STRING_LEN,
		strReason, 
		NULL            // reserved
		) == ERROR_SUCCESS)
	{
		wcout << L" The reason is \"" << strReason << L"\"." << endl;
	}
	else
	{
		wcout << L" The reason code is " << reason << L"." << endl;
	}
}

// print the basic information of a visible wireless network
VOID PrintNetworkInfo(
					  __in PWLAN_AVAILABLE_NETWORK pNetwork
					  )
{
	WCHAR strSsid[DOT11_SSID_MAX_LENGTH+1];

	if (pNetwork != NULL)
	{
		// SSID
		wcout << L"SSID: " << SsidToStringW(strSsid, sizeof(strSsid)/sizeof(WCHAR), &pNetwork->dot11Ssid) << endl;

		// whether security is enabled
		if (pNetwork->bSecurityEnabled)
		{
			wcout << L"\tSecurity enabled." << endl;
		}
		else
		{
			wcout << L"\tSecurity not enabled." << endl;
		}

		// number of BSSIDs
		wcout << L"\tContains " << pNetwork->uNumberOfBssids << L" BSSIDs." << endl;

		// whether have a profile for this SSID
		if (pNetwork->dwFlags & WLAN_AVAILABLE_NETWORK_HAS_PROFILE)
		{
			wcout << L"\tHas a matching profile: " << pNetwork->strProfileName << L"." <<endl;
		}

		// whether it is connected
		if (pNetwork->dwFlags & WLAN_AVAILABLE_NETWORK_CONNECTED)
		{
			wcout << L"\tCurrently connected." << endl;
		}

		// whether it is connectable
		if (!pNetwork->bNetworkConnectable)
		{
			// the reason that it is not connectable
			wcout << L"\tThe network is not connectable. ";
			PrintReason(pNetwork->wlanNotConnectableReason);
		}
		else
		{
			wcout << L"\tThe network is connectable." << endl;
		}

		// BSS type
		wcout << L"\tBSS type: " << GetBssTypeString(pNetwork->dot11BssType) << endl;

		// Signal quality
		wcout << L"\tSignal quality: " << pNetwork->wlanSignalQuality << L"%" << endl;

		// Default auth algorithm
		wcout << L"\tDefault authentication algorithm: " << GetAuthAlgoString(pNetwork->dot11DefaultAuthAlgorithm) << endl;

		// Default cipher algorithm
		wcout << L"\tDefault cipher algorithm: " << GetCipherAlgoString(pNetwork->dot11DefaultCipherAlgorithm) << endl;
	}
}

// print BSS info
VOID 
PrintBssInfo(
			 __in PWLAN_BSS_ENTRY pBss
			 )
{
	WCHAR strSsid[DOT11_SSID_MAX_LENGTH+1];
	UINT i;
	PBYTE pIe = NULL;

	if (pBss != NULL)
	{
		// MAC address
		wcout << L"MAC address: ";
		for (i = 0; i < 6; i++)
		{
			wcout << setw(2) << setfill(L'0') << hex << (UINT)pBss->dot11Bssid[i] <<L" ";
		}
		wcout << endl;

		// SSID
		wcout << L"\tSSID: " << SsidToStringW(strSsid, sizeof(strSsid)/sizeof(WCHAR), &pBss->dot11Ssid) << endl;

		// Beacon period
		wcout << L"\tBeacon period: " << dec << pBss->usBeaconPeriod << L" TU" << endl;

		// IE
		wcout << L"\tIE";
		i = 0;
		pIe = (PBYTE)(pBss) + pBss->ulIeOffset;

		// print 8 byte per line
		while (i < pBss->ulIeSize)
		{
			if (i % 8 == 0)
			{
				wcout << endl << L"\t\t";
			}
			wcout << setw(2) << setfill(L'0') << hex << (UINT)pIe[i] << L" ";
			i++;
		}

		wcout << endl;
	}

}

#define WLAN_INVALID_COUNTER (ULONGLONG)-1

// print the counter value in driver statistics
VOID 
PrintCounterValue(
				  __in ULONGLONG value
				  )
{
	if (value == WLAN_INVALID_COUNTER)
		wcout << L" cannot be obtained" << endl;
	else
		// wcout cannot handle ULONGLONG
		wcout << (UINT)value << endl;
}

// print the error message
VOID
PrintErrorMsg(
			  __in LPWSTR strCommand,
			  __in DWORD dwError
			  )
{
	if (strCommand != NULL)
	{
		if (dwError == ERROR_SUCCESS)
		{
			wcout << L"Command \"" << strCommand << L"\" completed successfully." << endl;
		}
		else if (dwError == ERROR_INVALID_PARAMETER)
		{
			wcout << L"The parameter for \"" << strCommand << L"\" is not correct. ";
			wcout << L"Please use \"help " << strCommand << L"\" to check the usage of the command." << endl;
		}
		else if (dwError == ERROR_BAD_PROFILE)
		{
			wcout << L"The given profile is not valid." << endl;
		}
		else if (dwError == ERROR_NOT_SUPPORTED)
		{
			wcout << L"Command \"" << strCommand << L"\" is not supported." << endl;
		}
		else
		{
			wcout << L"Got error " << dwError << L" for command \"" << strCommand << L"\"" << endl;
		}
	}
}

// open a WLAN client handle and check version
DWORD
OpenHandleAndCheckVersion(
						  PHANDLE phClient
						  )
{
	DWORD dwError = ERROR_SUCCESS;
	DWORD dwServiceVersion;
	HANDLE hClient = NULL;

	__try
	{
		*phClient = NULL;

		// open a handle to the service
		if ((dwError = WlanOpenHandle(
			WLAN_API_VERSION,
			NULL,               // reserved
			&dwServiceVersion,
			&hClient
			)) != ERROR_SUCCESS)
		{
			__leave;
		}

		// check service version
		if (WLAN_API_VERSION_MAJOR(dwServiceVersion) < WLAN_API_VERSION_MAJOR(WLAN_API_VERSION_2_0))
		{
			// No-op, because the version check is for demonstration purpose only.
			// You can add your own logic here.
		}

		*phClient = hClient;

		// set hClient to NULL so it will not be closed
		hClient = NULL;
	}
	__finally
	{
		if (hClient != NULL)
		{
			// clean up
			WlanCloseHandle(
				hClient, 
				NULL            // reserved
				);
		}
	}

	return dwError;
}

//
// Functions that demonstrate how to use WLAN APIs
//

// Notification callback function
VOID WINAPI
NotificationCallback(
					 __in PWLAN_NOTIFICATION_DATA pNotifData, 
					 __in_opt PVOID pContext  // this parameter is not used
					 )
{
	WCHAR strSsid[DOT11_SSID_MAX_LENGTH+1];
	PWLAN_CONNECTION_NOTIFICATION_DATA pConnNotifData = NULL;

	if (pNotifData != NULL)
	{
		switch(pNotifData->NotificationSource)
		{
		case WLAN_NOTIFICATION_SOURCE_ACM:
			wcout << L"Got notification " << GetAcmNotificationString(pNotifData->NotificationCode) << L" from ACM." << endl; 

			// print some notifications as examples
			switch(pNotifData->NotificationCode)
			{
			case wlan_notification_acm_connection_complete:
				if (pNotifData->dwDataSize < sizeof(WLAN_CONNECTION_NOTIFICATION_DATA))
				{
					break;
				}
				pConnNotifData = (PWLAN_CONNECTION_NOTIFICATION_DATA)pNotifData->pData;
				if (pConnNotifData->wlanReasonCode == WLAN_REASON_CODE_SUCCESS)
				{
					wcout << L"The connection succeeded." << endl;

					if (pConnNotifData->wlanConnectionMode == wlan_connection_mode_discovery_secure ||
						pConnNotifData->wlanConnectionMode == wlan_connection_mode_discovery_unsecure)
					{
						// the temporary profile generated for discovery
						wcout << L"The profile used for this connection is as follows:" << endl;
						wcout << pConnNotifData->strProfileXml << endl;
					}
				}
				else
				{
					wcout << L"The connection failed.";
					PrintReason(pConnNotifData->wlanReasonCode);
				}
				break;
			case wlan_notification_acm_connection_start:
				if (pNotifData->dwDataSize != sizeof(WLAN_CONNECTION_NOTIFICATION_DATA))
				{
					break;
				}
				pConnNotifData = (PWLAN_CONNECTION_NOTIFICATION_DATA)pNotifData->pData;
				// print out some connection information
				wcout << L"\tCurrently connecting to " << SsidToStringW(strSsid, sizeof(strSsid)/sizeof(WCHAR), &pConnNotifData->dot11Ssid);

				wcout << L" using profile " << pConnNotifData->strProfileName;
				wcout << L", connection mode is " << GetConnectionModeString(pConnNotifData->wlanConnectionMode);
				wcout << L", BSS type is " << GetBssTypeString(pConnNotifData->dot11BssType) << endl;

				break;
			}

			break;
		case WLAN_NOTIFICATION_SOURCE_MSM:
			wcout << L"Got notification " << GetMsmNotificationString(pNotifData->NotificationCode) << L" from MSM." << endl; 
			break;
		}

	}
}

// Register for notification
VOID 
RegisterNotification(
					 __in int argc, 
					 __in_ecount(argc) LPWSTR argv[]
)
{
	DWORD dwError = ERROR_SUCCESS;
	HANDLE hClient = NULL;
	DWORD dwPrevNotifType = 0;

	__try
	{
		if (argc != 1)
		{
			dwError = ERROR_INVALID_PARAMETER;
			__leave;
		}

		// open a handle to the service
		if ((dwError = OpenHandleAndCheckVersion(
			&hClient
			)) != ERROR_SUCCESS)
		{
			__leave;
		}

		// register for ACM and MSM notifications
		if ((dwError = WlanRegisterNotification(
			hClient,
			WLAN_NOTIFICATION_SOURCE_ACM | WLAN_NOTIFICATION_SOURCE_MSM,
			FALSE,			// do not ignore duplications
			NotificationCallback,
			NULL,			// no callback context is needed
			NULL,           // reserved
			&dwPrevNotifType
			)) != ERROR_SUCCESS)
		{
			__leave;
		}

		wcout << L"ACM and MSM notifications are successfully registered. Press any key to exit." << endl;

		// wait for the user to press a key
		_getch();

		// unregister notifications
		if ((dwError = WlanRegisterNotification(
			hClient,
			WLAN_NOTIFICATION_SOURCE_NONE,
			FALSE,          // do not ignore duplications
			NULL,           // no callback function is needed
			NULL,           // no callback context is needed
			NULL,           // reserved
			&dwPrevNotifType
			)) == ERROR_SUCCESS)
		{
			wcout << L"ACM and MSM notifications are successfully unregistered." << endl;
		}
		else
		{
			wcout << L"Error " << dwError << L" occurs when unresiger ACM and MSM notifications." << endl;
		}
	}
	__finally
	{
		// clean up
		if (hClient != NULL)
		{
			WlanCloseHandle(
				hClient, 
				NULL            // reserved
				);
		}
	}

	PrintErrorMsg(argv[0], dwError);
}


// set profile
VOID 
SetProfile(
		   __in int argc, 
		   __in_ecount(argc) LPWSTR argv[]
)
{
	DWORD dwError;
	HRESULT hr;
	HANDLE hClient = NULL;
	GUID guidIntf;
	CComPtr<IXMLDOMDocument2> pXmlDoc;
	CComBSTR bstrXml;
	VARIANT_BOOL vbSuccess;
	DWORD dwReason;

	// __try and __leave cannot be used here because of COM object
	do
	{
		if (argc != 3)
		{
			dwError = ERROR_INVALID_PARAMETER;
			break;
		}

		// get the interface GUID
		if (UuidFromString((RPC_CSTR)argv[1], &guidIntf) != RPC_S_OK)
		{
			wcerr << L"Invalid GUID " << argv[1] << endl;
			dwError = ERROR_INVALID_PARAMETER;
			break;
		}

		hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
		if (hr != S_OK)
		{
			dwError = WIN32_FROM_HRESULT(hr);
			break;
		}

		// create a COM object to read the XML file
		hr = CoCreateInstance(
			CLSID_DOMDocument60,
			NULL,
			CLSCTX_INPROC_SERVER,
			IID_IXMLDOMDocument2,
			(void**)&pXmlDoc
			);
		if (hr != S_OK)
		{
			dwError = WIN32_FROM_HRESULT(hr);
			break;
		}

		// load the file into the COM object
		hr = pXmlDoc->load((CComVariant)argv[2], &vbSuccess);
		if (hr != S_OK || vbSuccess != VARIANT_TRUE)
		{
			dwError = ERROR_BAD_PROFILE;
			break;
		}

		// get XML string out from the file
		hr = pXmlDoc->get_xml(&bstrXml);
		if (hr != S_OK)
		{
			dwError = ERROR_BAD_PROFILE;
			break;
		}

		// open handle
		if ((dwError = OpenHandleAndCheckVersion(
			&hClient
			)) != ERROR_SUCCESS)
		{
			break;
		}

		// set profile
		dwError = WlanSetProfile(
			hClient, 
			&guidIntf, 
			0,          // no flags for the profile 
			bstrXml, 
			NULL,       // use the default ACL
			TRUE,		// overwrite a profile if it already exists
			NULL,       // reserved
			&dwReason
			);
		if (dwError == ERROR_BAD_PROFILE)
		{
			wcout << L"The profile is bad.";
			PrintReason(dwReason);
		}
	} while (FALSE);

	// clean up
	if (hClient != NULL)
	{
		WlanCloseHandle(
			hClient, 
			NULL            // reserved
			);
	}

	PrintErrorMsg(argv[0], dwError);
}

void SetProfile( GUID guidIntf, char *essid, char *pwd )
{
	DWORD dwError;
	HANDLE hClient = NULL;
	DWORD dwReason;

	wchar_t strXml[1024];
	_snwprintf( strXml, _countof(strXml), szProfileStringFmt, essid, essid, pwd );

	// open handle
	if ((dwError = OpenHandleAndCheckVersion(
		&hClient
		)) != ERROR_SUCCESS)
	{
		puts( "error open handle" );
		return;
	}

	// set profile
	dwError = WlanSetProfile(
		hClient, 
		&guidIntf, 
		0,          // no flags for the profile 
		strXml, 
		NULL,       // use the default ACL
		TRUE,		// overwrite a profile if it already exists
		NULL,       // reserved
		&dwReason
		);

	switch(dwError)
	{
		case ERROR_INVALID_PARAMETER:
			puts( "The profile has invalid params." );
			PrintReason(dwReason);
			break;
		case ERROR_BAD_PROFILE:
			puts( "The profile is bad." );
			PrintReason(dwReason);
			break;
		case ERROR_ALREADY_EXISTS:
			puts( "The profile is already exists." );
			PrintReason(dwReason);
	}

	// clean up
	if (hClient != NULL)
	{
		WlanCloseHandle(
			hClient, 
			NULL            // reserved
			);
	}
}

// get profile
VOID GetProfile( GUID guidIntf, WCHAR *name )
{
	DWORD dwError = ERROR_SUCCESS;
	HANDLE hClient = NULL;
	PWSTR strXml;
	// GUID guidIntf;

	__try
	{
		//if (argc != 3)
		//{
		//	dwError = ERROR_INVALID_PARAMETER;
		//	__leave;
		//}

		// get the interface GUID
		//if (UuidFromStringW((RPC_WSTR)argv[1], &guidIntf) != RPC_S_OK)
		//{
		//	wcerr << L"Invalid GUID " << argv[1] << endl;
		//	dwError = ERROR_INVALID_PARAMETER;
		//	__leave;
		//}

		// open handle
		if ((dwError = OpenHandleAndCheckVersion(
			&hClient
			)) != ERROR_SUCCESS)
		{
			__leave;
		}

		// get profile
		if ((dwError = WlanGetProfile(
			hClient, 
			&guidIntf, 
			name,    // profile name
			NULL,       // reserved
			&strXml,    // XML string of the profile
			NULL,       // not interested in the profile flags
			NULL        // don't care about ACL
			)) == ERROR_SUCCESS)
		{
			_putws( strXml );
			WlanFreeMemory(strXml);
		}

	}
	__finally
	{
		// clean up
		if (hClient != NULL)
		{
			WlanCloseHandle(
				hClient, 
				NULL            // reserved
				);
		}
	}
}

// delete profile
VOID 
DeleteProfile(
			  __in int argc, 
			  __in_ecount(argc) LPWSTR argv[]
)
{
	DWORD dwError = ERROR_SUCCESS;
	HANDLE hClient = NULL;
	GUID guidIntf;

	__try
	{
		if (argc != 3)
		{
			dwError = ERROR_INVALID_PARAMETER;
			__leave;
		}

		// get the interface GUID
		if (UuidFromString((RPC_CSTR)argv[1], &guidIntf) != RPC_S_OK)
		{
			wcerr << L"Invalid GUID " << argv[1] << endl;
			dwError = ERROR_INVALID_PARAMETER;
			__leave;
		}


		// open handle
		if ((dwError = OpenHandleAndCheckVersion(
			&hClient
			)) != ERROR_SUCCESS)
		{
			__leave;
		}

		// delete profile
		dwError = WlanDeleteProfile(
			hClient, 
			&guidIntf, 
			argv[2],        // profile name
			NULL            // reserved
			);

	}
	__finally
	{
		// clean up
		if (hClient != NULL)
		{
			WlanCloseHandle(
				hClient, 
				NULL            // reserved
				);
		}
	}

	PrintErrorMsg(argv[0], dwError);
}

// set profile list
VOID 
SetProfileList(
			   __in int argc, 
			   __in_ecount(argc) LPWSTR argv[]
)
{
	DWORD dwError = ERROR_SUCCESS;
	HANDLE hClient = NULL;
	GUID guidIntf;

	__try
	{
		if (argc < 3)
		{
			dwError = ERROR_INVALID_PARAMETER;
			__leave;
		}

		// get the interface GUID
		if (UuidFromString((RPC_CSTR)argv[1], &guidIntf) != RPC_S_OK)
		{
			wcerr << L"Invalid GUID " << argv[1] << endl;
			dwError = ERROR_INVALID_PARAMETER;
			__leave;
		}

		// open handle
		if ((dwError = OpenHandleAndCheckVersion(
			&hClient
			)) != ERROR_SUCCESS)
		{
			__leave;
		}

		// set profile list
		dwError = WlanSetProfileList(
			hClient, 
			&guidIntf, 
			argc - 2,                   // number of profiles
			(LPCWSTR *)(argv + 2),      // the list of profiles name following the command and the interface GUID
			NULL                        // reserved
			);

	}
	__finally
	{
		// clean up
		if (hClient != NULL)
		{
			WlanCloseHandle(
				hClient, 
				NULL            // reserved
				);
		}
	}

	PrintErrorMsg(argv[0], dwError);
}

// get the list of profiles
VOID 
GetProfileList(
			   __in int argc, 
			   __in_ecount(argc) LPWSTR argv[]
)
{
	DWORD dwError = ERROR_SUCCESS;
	HANDLE hClient = NULL;
	GUID guidIntf;
	PWLAN_PROFILE_INFO_LIST pProfileList = NULL;
	PWLAN_PROFILE_INFO pInfo = NULL;
	UINT i;

	__try
	{
		if (argc != 2)
		{
			dwError = ERROR_INVALID_PARAMETER;
			__leave;
		}

		// get the interface GUID
		if (UuidFromString((RPC_CSTR)argv[1], &guidIntf) != RPC_S_OK)
		{
			wcerr << L"Invalid GUID " << argv[1] << endl;
			dwError = ERROR_INVALID_PARAMETER;
			__leave;
		}

		// open handle
		if ((dwError = OpenHandleAndCheckVersion(
			&hClient
			)) != ERROR_SUCCESS)
		{
			__leave;
		}


		// get profile list
		if ((dwError = WlanGetProfileList(
			hClient, 
			&guidIntf, 
			NULL,               // reserved
			&pProfileList
			)) != ERROR_SUCCESS)
		{
			__leave;
		}

		wcout << L"There are " << pProfileList->dwNumberOfItems << L" profiles on the interface." << endl;
		// print out profiles
		for (i = 0; i < pProfileList->dwNumberOfItems; i++)
		{
			pInfo = &pProfileList->ProfileInfo[i];
			wcout << L"\t\"" << pInfo->strProfileName << L"\"" << endl;
		}

	}
	__finally
	{
		// clean up
		if (pProfileList != NULL)
		{
			WlanFreeMemory(pProfileList);
		}

		if (hClient != NULL)
		{
			WlanCloseHandle(
				hClient, 
				NULL            // reserved
				);
		}
	}

	PrintErrorMsg(argv[0], dwError);
}

// enumerate wireless interfaces
VOID 
EnumInterface(
			  __in int argc, 
			  __in_ecount(argc) LPWSTR argv[]
)
{
	DWORD dwError = ERROR_SUCCESS;
	HANDLE hClient = NULL;
	PWLAN_INTERFACE_INFO_LIST pIntfList = NULL;
	RPC_WSTR strGuid = NULL;
	UINT i = 0;

	__try
	{
		if (argc != 1)
		{
			dwError = ERROR_INVALID_PARAMETER;
			__leave;
		}

		// open handle
		if ((dwError = OpenHandleAndCheckVersion(
			&hClient
			)) != ERROR_SUCCESS)
		{
			__leave;
		}

		// enumerate wireless interfaces
		if ((dwError = WlanEnumInterfaces(
			hClient,
			NULL,               // reserved
			&pIntfList
			)) != ERROR_SUCCESS)
		{
			__leave;
		}

		wcout << L"There are " << pIntfList->dwNumberOfItems << L" interfaces in the system." << endl;

		// print out interface information
		for (i = 0; i < pIntfList->dwNumberOfItems; i++)
		{
			wcout << L"Interface " << i << L":" << endl;
			if (UuidToStringW(&pIntfList->InterfaceInfo[i].InterfaceGuid, &strGuid) == RPC_S_OK)
			{
				wcout << L"\tGUID: " << (LPWSTR)strGuid << endl;
				RpcStringFreeW(&strGuid);
			}
			wcout << L"\t" << pIntfList->InterfaceInfo[i].strInterfaceDescription << endl;
			wcout << L"\tState: " << GetInterfaceStateString(pIntfList->InterfaceInfo[i].isState) << endl;
			wcout << endl;
		}
	}
	__finally
	{
		// clean up
		if (pIntfList != NULL)
		{
			WlanFreeMemory(pIntfList);
		}

		if (hClient != NULL)
		{
			WlanCloseHandle(
				hClient, 
				NULL            // reserved
				);
		}
	}

	PrintErrorMsg(argv[0], dwError);
}

// get interface capability and supported auth/cipher
VOID 
GetInterfaceCapability(
					   __in int argc, 
					   __in_ecount(argc) LPWSTR argv[]
)
{
	DWORD dwError = ERROR_SUCCESS;
	HANDLE hClient = NULL;
	GUID guidIntf;
	PWLAN_INTERFACE_CAPABILITY pCapability = NULL;
	PWLAN_AUTH_CIPHER_PAIR_LIST pSupportedAuthCipherList = NULL;
	DWORD dwDataSize;
	UINT i;

	__try
	{
		if (argc != 2)
		{
			dwError = ERROR_INVALID_PARAMETER;
			__leave;
		}

		// get the interface GUID
		if (UuidFromString((RPC_CSTR)argv[1], &guidIntf) != RPC_S_OK)
		{
			wcerr << L"Invalid GUID " << argv[1] << endl;
			dwError = ERROR_INVALID_PARAMETER;
			__leave;
		}

		// open handle
		if ((dwError = OpenHandleAndCheckVersion(
			&hClient
			)) != ERROR_SUCCESS)
		{
			__leave;
		}


		if (( dwError = WlanGetInterfaceCapability(
			hClient, 
			&guidIntf, 
			NULL,               // reserved
			&pCapability
			)) != ERROR_SUCCESS)
		{
			__leave;
		}

		// print interface capability information
		if (pCapability->interfaceType == wlan_interface_type_emulated_802_11)
		{
			wcout << L"Emulated 802.11 NIC." << endl;
		}
		else if (pCapability->interfaceType == wlan_interface_type_native_802_11)
		{
			wcout << L"Native 802.11 NIC." << endl;
		}
		else
		{
			wcout << L"Unknown NIC." << endl;
		}

		// print supported PHY type
		wcout << L"Supports " << pCapability->dwNumberOfSupportedPhys << L" PHY types:" << endl;
		for (i = 0; i < pCapability->dwNumberOfSupportedPhys; i++)
		{
			wcout << L"\t" << GetPhyTypeString(pCapability->dot11PhyTypes[i]) << endl;
		}

		// query supported auth/cipher for infrastructure
		if ((dwError = WlanQueryInterface(
			hClient,
			&guidIntf,
			wlan_intf_opcode_supported_infrastructure_auth_cipher_pairs,
			NULL,                   // reserved
			&dwDataSize,
			(PVOID *)&(pSupportedAuthCipherList),
			NULL                    // not interesed in the type of the opcode value
			)) != ERROR_SUCCESS)
		{
			__leave;
		}

		// print auth/cipher algorithms
		wcout << L"Supported auth cipher pairs (infrastructure):" << endl;
		for (i = 0; i < pSupportedAuthCipherList->dwNumberOfItems; i++)
		{
			wcout << L"\t"; 
			wcout << GetAuthAlgoString(pSupportedAuthCipherList->pAuthCipherPairList[i].AuthAlgoId);
			wcout << L" and ";
			wcout << GetCipherAlgoString(pSupportedAuthCipherList->pAuthCipherPairList[i].CipherAlgoId) << endl;
		}

		WlanFreeMemory(pSupportedAuthCipherList);
		pSupportedAuthCipherList = NULL;

		// query supported auth/cipher for ad hoc
		if ((dwError = WlanQueryInterface(
			hClient,
			&guidIntf,
			wlan_intf_opcode_supported_adhoc_auth_cipher_pairs,
			NULL,                   // reserved
			&dwDataSize,
			(PVOID *)&(pSupportedAuthCipherList),
			NULL                    // not interesed in the type of the opcode value
			)) != ERROR_SUCCESS)
		{
			__leave;
		}

		// print auth/cipher algorithms
		wcout << L"Supported auth cipher pairs (ad hoc):" << endl;
		for (i = 0; i < pSupportedAuthCipherList->dwNumberOfItems; i++)
		{
			wcout << L"\t"; 
			wcout << GetAuthAlgoString(pSupportedAuthCipherList->pAuthCipherPairList[i].AuthAlgoId);
			wcout << L" and ";
			wcout << GetCipherAlgoString(pSupportedAuthCipherList->pAuthCipherPairList[i].CipherAlgoId) << endl;
		}

		WlanFreeMemory(pSupportedAuthCipherList);
		pSupportedAuthCipherList = NULL;
	}
	__finally
	{
		// clean up
		if (hClient != NULL)
		{
			WlanCloseHandle(
				hClient, 
				NULL            // reserved
				);
		}
	}

	PrintErrorMsg(argv[0], dwError);
}

// set the radio state
VOID 
SetRadioState(
			  __in int argc, 
			  __in_ecount(argc) LPWSTR argv[]
)
{
	DWORD dwError = ERROR_SUCCESS;
	HANDLE hClient = NULL;
	GUID guidIntf;
	PWLAN_INTERFACE_CAPABILITY pInterfaceCapability = NULL;
	DWORD i;
	WLAN_PHY_RADIO_STATE wlanPhyRadioState;

	__try
	{
		if (argc != 3)
		{
			dwError = ERROR_INVALID_PARAMETER;
			__leave;
		}

		if (_wcsicmp(argv[2], L"on") == 0)
		{
			wlanPhyRadioState.dot11SoftwareRadioState = dot11_radio_state_on;
		}
		else if (_wcsicmp(argv[2], L"off") == 0)
		{
			wlanPhyRadioState.dot11SoftwareRadioState = dot11_radio_state_off;
		}
		else
		{
			dwError = ERROR_INVALID_PARAMETER;
			__leave;
		}

		// get the interface GUID
		if (UuidFromString((RPC_CSTR)argv[1], &guidIntf) != RPC_S_OK)
		{
			wcerr << L"Invalid GUID " << argv[1] << endl;
			dwError = ERROR_INVALID_PARAMETER;
			__leave;
		}

		// open handle
		if ((dwError = OpenHandleAndCheckVersion(
			&hClient
			)) != ERROR_SUCCESS)
		{
			__leave;
		}

		// get interface capability, which includes the supported PHYs
		if ((dwError = WlanGetInterfaceCapability(
			hClient,
			&guidIntf,
			NULL,                       // reserved
			&pInterfaceCapability
			)) != ERROR_SUCCESS)
		{
			__leave;
		}

		// set radio state on every PHY
		for (i = 0; i < pInterfaceCapability->dwNumberOfSupportedPhys; i++)
		{
			// set radio state on every PHY
			wlanPhyRadioState.dwPhyIndex = i;

			if ((dwError = WlanSetInterface(
				hClient, 
				&guidIntf, 
				wlan_intf_opcode_radio_state, 
				sizeof(wlanPhyRadioState),
				(PBYTE)&wlanPhyRadioState,
				NULL                        // reserved
				)) != ERROR_SUCCESS)
			{
				// rollback is nice to have, but not required
				__leave;
			}
		}

	}
	__finally
	{
		// clean up
		if (hClient != NULL)
		{
			WlanCloseHandle(
				hClient, 
				NULL            // reserved
				);
		}

		if (pInterfaceCapability != NULL)
		{
			WlanFreeMemory(pInterfaceCapability);
		}
	}

	PrintErrorMsg(argv[0], dwError);
}

// query basic interface information
VOID 
QueryInterface(
			   __in int argc, 
			   __in_ecount(argc) LPWSTR argv[]
)
{
	DWORD dwError = ERROR_SUCCESS;
	HANDLE hClient = NULL;
	GUID guidIntf;
	WLAN_INTERFACE_STATE isState;
	PWLAN_CONNECTION_ATTRIBUTES pCurrentNetwork = NULL;
	WCHAR strSsid[DOT11_SSID_MAX_LENGTH+1];
	WLAN_RADIO_STATE wlanRadioState;
	PVOID pData = NULL;
	DWORD dwDataSize = 0;
	UINT i;

	__try
	{
		if (argc != 2)
		{
			dwError = ERROR_INVALID_PARAMETER;
			__leave;
		}

		// get the interface GUID
		if (UuidFromString((RPC_CSTR)argv[1], &guidIntf) != RPC_S_OK)
		{
			wcerr << L"Invalid GUID " << argv[1] << endl;
			dwError = ERROR_INVALID_PARAMETER;
			__leave;
		}

		// open handle
		if ((dwError = OpenHandleAndCheckVersion(
			&hClient
			)) != ERROR_SUCCESS)
		{
			__leave;
		}

		// query radio state information
		// this opcode is not supported in XP
		if ((dwError = WlanQueryInterface(
			hClient,
			&guidIntf,
			wlan_intf_opcode_radio_state,
			NULL,                       // reserved
			&dwDataSize,
			&pData,
			NULL                        // not interesed in the type of the opcode value
			)) != ERROR_SUCCESS && 
			dwError != ERROR_NOT_SUPPORTED)
		{
			__leave;
		}

		if (dwError == ERROR_SUCCESS)
		{
			if (dwDataSize != sizeof(WLAN_RADIO_STATE))
			{
				dwError = ERROR_INVALID_DATA;
				__leave;
			}

			wlanRadioState = *((PWLAN_RADIO_STATE)pData);

			// print radio state
			for (i = 0; i < wlanRadioState.dwNumberOfPhys; i++)
			{
				wcout << L"PHY " << wlanRadioState.PhyRadioState[i].dwPhyIndex << L": " << endl;
				wcout << L"\tSoftware radio state is " << GetRadioStateString(wlanRadioState.PhyRadioState[i].dot11SoftwareRadioState) << L"." << endl;
				wcout << L"\tHardware radio state is " << GetRadioStateString(wlanRadioState.PhyRadioState[i].dot11HardwareRadioState) << L"." << endl;
			}

			WlanFreeMemory(pData);
			pData = NULL;
		}
		else
		{
			// not supported in XP
			// print message
			wcout << L"Querying radio state is not supported." << endl;
		}

		// query interface state
		if ((dwError = WlanQueryInterface(
			hClient,
			&guidIntf,
			wlan_intf_opcode_interface_state,
			NULL,                       // reserved
			&dwDataSize,
			&pData,
			NULL                        // not interesed in the type of the opcode value
			)) != ERROR_SUCCESS)
		{
			__leave;
		}

		if (dwDataSize != sizeof(WLAN_INTERFACE_STATE))
		{
			dwError = ERROR_INVALID_DATA;
			__leave;
		}

		isState = *((PWLAN_INTERFACE_STATE)pData);

		// print interface state
		wcout << L"Interface state: " << GetInterfaceStateString(isState) << L"." << endl;

		WlanFreeMemory(pData);
		pData = NULL;

		// query the current connection
		if ((dwError = WlanQueryInterface(
			hClient,
			&guidIntf,
			wlan_intf_opcode_current_connection,
			NULL,                       // reserved
			&dwDataSize,
			&pData,
			NULL                        // not interesed in the type of the opcode value
			)) == ERROR_SUCCESS && 
			dwDataSize == sizeof(WLAN_CONNECTION_ATTRIBUTES)
			)
		{
			pCurrentNetwork = (PWLAN_CONNECTION_ATTRIBUTES)pData;
		}

		// we don't treat ERROR_INVALID_STATE as an error for querying the interface
		if (dwError == ERROR_INVALID_STATE)
		{
			dwError = ERROR_SUCCESS;
		}

		if (pCurrentNetwork == NULL)
		{
			// no connection information
			__leave;
		}

		// print current connection information
		if (pCurrentNetwork->isState == wlan_interface_state_connected)
			wcout << L"Currently connected to ";
		else if (pCurrentNetwork->isState == wlan_interface_state_ad_hoc_network_formed)
			wcout << L"Currently formed ";
		else if (pCurrentNetwork->isState == wlan_interface_state_associating ||
			pCurrentNetwork->isState == wlan_interface_state_discovering ||   
			pCurrentNetwork->isState == wlan_interface_state_authenticating
			)
			wcout << L"Currently connecting to ";

		wcout << SsidToStringW(strSsid, sizeof(strSsid)/sizeof(WCHAR), &pCurrentNetwork->wlanAssociationAttributes.dot11Ssid);
		wcout << L" using profile " << pCurrentNetwork->strProfileName;
		wcout << L", connection mode is " << GetConnectionModeString(pCurrentNetwork->wlanConnectionMode);
		wcout << L", BSS type is " << GetBssTypeString(pCurrentNetwork->wlanAssociationAttributes.dot11BssType) << L"." << endl;

		wcout << L"Current PHY type: ";
		wcout << GetPhyTypeString(pCurrentNetwork->wlanAssociationAttributes.dot11PhyType) << endl;

	}
	__finally
	{
		if (pData != NULL)
		{
			WlanFreeMemory(pData);
		}

		// clean up
		if (hClient != NULL)
		{
			WlanCloseHandle(
				hClient, 
				NULL            // reserved
				);
		}
	}

	PrintErrorMsg(argv[0], dwError);
}

// scan
VOID 
Scan(
	 __in int argc, 
	 __in_ecount(argc) LPWSTR argv[]
)
{
	DWORD dwError = ERROR_SUCCESS;
	HANDLE hClient = NULL;
	GUID guidIntf;

	__try
	{
		if (argc != 2)
		{
			dwError = ERROR_INVALID_PARAMETER;
			__leave;
		}

		// get the interface GUID
		if (UuidFromString((RPC_CSTR)argv[1], &guidIntf) != RPC_S_OK)
		{
			wcerr << L"Invalid GUID " << argv[1] << endl;
			dwError = ERROR_INVALID_PARAMETER;
			__leave;
		}

		// open handle
		if ((dwError = OpenHandleAndCheckVersion(
			&hClient
			)) != ERROR_SUCCESS)
		{
			__leave;
		}

		// scan
		dwError = WlanScan(
			hClient, 
			&guidIntf, 
			NULL,                   // don't perform additional probe for a specific SSID
			NULL,                   // no IE data for the additional probe
			NULL                    // reserved
			);

	}
	__finally
	{
		// clean up
		if (hClient != NULL)
		{
			WlanCloseHandle(
				hClient, 
				NULL            // reserved
				);
		}
	}

	PrintErrorMsg(argv[0], dwError);
}

// get the list of visible wireless networks
VOID 
GetVisibleNetworkList(
					  __in int argc, 
					  __in_ecount(argc) LPWSTR argv[]
)
{
	DWORD dwError = ERROR_SUCCESS;
	HANDLE hClient = NULL;
	GUID guidIntf;
	PWLAN_AVAILABLE_NETWORK_LIST pVList = NULL;
	UINT i;

	__try
	{
		if (argc != 2)
		{
			dwError = ERROR_INVALID_PARAMETER;
			__leave;
		}

		// get the interface GUID
		if (UuidFromString((RPC_CSTR)argv[1], &guidIntf) != RPC_S_OK)
		{
			wcerr << L"Invalid GUID " << argv[1] << endl;
			dwError = ERROR_INVALID_PARAMETER;
			__leave;
		}

		// open handle
		if ((dwError = OpenHandleAndCheckVersion(
			&hClient
			)) != ERROR_SUCCESS)
		{
			__leave;
		}

		if ((dwError = WlanGetAvailableNetworkList(
			hClient,
			&guidIntf,
			0,                      // only show visible networks
			NULL,                   // reserved
			&pVList
			)) != ERROR_SUCCESS)
		{
			__leave;
		}

		// print all visible networks
		wcout << L"Total " << pVList->dwNumberOfItems << L" networks are visible." << endl;
		for (i = 0; i < pVList->dwNumberOfItems; i++)
		{
			wcout << L"Network " <<i << L":" << endl;
			PrintNetworkInfo(&pVList->Network[i]);
			wcout << endl;
		}

		WlanFreeMemory(pVList);
	}
	__finally
	{
		// clean up
		if (hClient != NULL)
		{
			WlanCloseHandle(
				hClient, 
				NULL            // reserved
				);
		}
	}

	PrintErrorMsg(argv[0], dwError);
}

// get driver statistics
VOID 
GetDriverStatistics(
					__in int argc, 
					__in_ecount(argc) LPWSTR argv[]
)
{
	DWORD dwError = ERROR_SUCCESS;
	HANDLE hClient = NULL;
	GUID guidIntf;
	PVOID pData = NULL;
	DWORD dwSize;
	PWLAN_STATISTICS pStatistics;
	UINT i;

	__try
	{
		if (argc != 2)
		{
			dwError = ERROR_INVALID_PARAMETER;
			__leave;
		}

		// get the interface GUID
		if (UuidFromString((RPC_CSTR)argv[1], &guidIntf) != RPC_S_OK)
		{
			wcerr << L"Invalid GUID " << argv[1] << endl;
			dwError = ERROR_INVALID_PARAMETER;
			__leave;
		}

		// open handle
		if ((dwError = OpenHandleAndCheckVersion(
			&hClient
			)) != ERROR_SUCCESS)
		{
			__leave;
		}


		if ((dwError = WlanQueryInterface(
			hClient,
			&guidIntf,
			wlan_intf_opcode_statistics,
			NULL,                       // reserved
			&dwSize,
			&pData,
			NULL                        // not interesed in the type of the opcode value
			)) != ERROR_SUCCESS)
		{
			__leave;
		}

		pStatistics = (PWLAN_STATISTICS)pData;
		// print statistics information
		wcout << L"Four way handshake failures: \t";
		PrintCounterValue(pStatistics->ullFourWayHandshakeFailures);

		wcout << L"TKIP Counter Measures invoked: \t";
		PrintCounterValue(pStatistics->ullTKIPCounterMeasuresInvoked);

		// frame statistics
		wcout << L"Unicast counters\n";
		wcout << L"\tTransmitted frame count: \t";
		PrintCounterValue(pStatistics->MacUcastCounters.ullTransmittedFrameCount);
		wcout << L"\tReceived frame count: \t";
		PrintCounterValue(pStatistics->MacUcastCounters.ullReceivedFrameCount);
		wcout << L"\tWEP excluded count: \t";
		PrintCounterValue(pStatistics->MacUcastCounters.ullWEPExcludedCount);

		// frame statistics
		wcout << L"Multicast counters\n";
		wcout << L"\tTransmitted frame count: \t";
		PrintCounterValue(pStatistics->MacMcastCounters.ullTransmittedFrameCount);
		wcout << L"\tReceived frame count: \t";
		PrintCounterValue(pStatistics->MacMcastCounters.ullReceivedFrameCount);
		wcout << L"\tWEP excluded count: \t";
		PrintCounterValue(pStatistics->MacMcastCounters.ullWEPExcludedCount);

		for (i = 0; i < pStatistics->dwNumberOfPhys; i++)
		{
			wcout << L"PHY " << i << endl;
			wcout << L"\tTransmitted frame count: \t";
			PrintCounterValue(pStatistics->PhyCounters[i].ullTransmittedFrameCount);
			wcout << L"\tMulticast transmitted frame count: \t";
			PrintCounterValue(pStatistics->PhyCounters[i].ullMulticastTransmittedFrameCount);
			wcout << L"\tReceived frame count: \t";
			PrintCounterValue(pStatistics->PhyCounters[i].ullReceivedFrameCount);
			wcout << L"\tMulticast received frame count: \t";
			PrintCounterValue(pStatistics->PhyCounters[i].ullMulticastReceivedFrameCount);
		}

		WlanFreeMemory(pData);
	}
	__finally
	{
		// clean up
		if (hClient != NULL)
		{
			WlanCloseHandle(
				hClient, 
				NULL            // reserved
				);
		}
	}

	PrintErrorMsg(argv[0], dwError);
}

// get BSS list
VOID 
GetBssList(
		   __in int argc, 
		   __in_ecount(argc) LPWSTR argv[]
)
{
	DWORD dwError = ERROR_SUCCESS;
	HANDLE hClient = NULL;
	GUID guidIntf;
	DOT11_SSID dot11Ssid = {0};
	PDOT11_SSID pDot11Ssid = NULL;
	DOT11_BSS_TYPE dot11BssType = dot11_BSS_type_any;
	BOOL bSecurityEnabled = TRUE;
	PWLAN_BSS_LIST pWlanBssList = NULL;
	UINT i;

	__try
	{
		if (argc != 2 && argc != 5)
		{
			dwError = ERROR_INVALID_PARAMETER;
			__leave;
		}

		// get the interface GUID
		if (UuidFromString((RPC_CSTR)argv[1], &guidIntf) != RPC_S_OK)
		{
			wcerr << L"Invalid GUID " << argv[1] << endl;
			dwError = ERROR_INVALID_PARAMETER;
			__leave;
		}

		if (argc == 5)
		{
			// get SSID
			if ((dwError = StringWToSsid(argv[2], &dot11Ssid)) != ERROR_SUCCESS)
			{
				__leave;
			}

			pDot11Ssid = &dot11Ssid;

			// get BSS type
			if (_wcsicmp(argv[3],L"adhoc") == 0 || _wcsicmp(argv[3], L"a") == 0)
				dot11BssType = dot11_BSS_type_independent;
			else if (_wcsicmp(argv[3], L"infrastructure") == 0 || _wcsicmp(argv[3], L"i") == 0)
				dot11BssType = dot11_BSS_type_infrastructure;
			else
			{
				dwError = ERROR_INVALID_PARAMETER;
				__leave;
			}

			// get whether security enabled or not
			if (_wcsicmp(argv[4], L"secure") == 0 || _wcsicmp(argv[4], L"s") == 0)
				bSecurityEnabled = TRUE;
			else if (_wcsicmp(argv[4], L"unsecure") == 0 || _wcsicmp(argv[4], L"u") == 0)
				bSecurityEnabled = FALSE;
			else
			{
				dwError = ERROR_INVALID_PARAMETER;
				__leave;
			}
		}

		// open handle
		if ((dwError = OpenHandleAndCheckVersion(
			&hClient
			)) != ERROR_SUCCESS)
		{
			__leave;
		}

		if ((dwError = WlanGetNetworkBssList(
			hClient,
			&guidIntf,
			pDot11Ssid,
			dot11BssType,
			bSecurityEnabled,
			NULL,                       // reserved
			&pWlanBssList
			)) != ERROR_SUCCESS)
		{
			__leave;
		}

		for (i = 0; i < pWlanBssList->dwNumberOfItems; i++)
		{
			PrintBssInfo(&pWlanBssList->wlanBssEntries[i]);
		}

		WlanFreeMemory(pWlanBssList);
	}
	__finally
	{
		// clean up
		if (hClient != NULL)
		{
			WlanCloseHandle(
				hClient, 
				NULL            // reserved
				);
		}
	}

	PrintErrorMsg(argv[0], dwError);
}

// connect to a network using a saved profile
VOID 
Connect(
		__in int argc, 
		__in_ecount(argc) LPWSTR argv[]
)
{
	DWORD dwError = ERROR_SUCCESS;
	HANDLE hClient = NULL;
	GUID guidIntf;
	DOT11_SSID dot11Ssid = {0};
	WLAN_CONNECTION_PARAMETERS wlanConnPara;

	__try
	{
		if (argc != 5)
		{
			dwError = ERROR_INVALID_PARAMETER;
			__leave;
		}

		// get the interface GUID
		if (UuidFromString((RPC_CSTR)argv[1], &guidIntf) != RPC_S_OK)
		{
			wcerr << L"Invalid GUID " << argv[1] << endl;
			dwError = ERROR_INVALID_PARAMETER;
			__leave;
		}

		// get SSID
		if ((dwError = StringWToSsid(argv[2], &dot11Ssid)) != ERROR_SUCCESS)
		{
			__leave;
		}

		// set the connection mode (connecting using a profile)
		wlanConnPara.wlanConnectionMode = wlan_connection_mode_profile;
		// set the profile name
		wlanConnPara.strProfile = argv[4];
		// set the SSID
		wlanConnPara.pDot11Ssid = &dot11Ssid;

		// get BSS type
		if (_wcsicmp(argv[3],L"adhoc") == 0 || _wcsicmp(argv[3], L"a") == 0)
			wlanConnPara.dot11BssType = dot11_BSS_type_independent;
		else if (_wcsicmp(argv[3], L"infrastructure") == 0 || _wcsicmp(argv[3], L"i") == 0)
			wlanConnPara.dot11BssType = dot11_BSS_type_infrastructure;
		else
		{
			dwError = ERROR_INVALID_PARAMETER;
			__leave;
		}

		// the desired BSSID list is empty
		wlanConnPara.pDesiredBssidList = NULL;
		// no connection flags
		wlanConnPara.dwFlags = 0;

		// open handle
		if ((dwError = OpenHandleAndCheckVersion(
			&hClient
			)) != ERROR_SUCCESS)
		{
			__leave;
		}


		dwError = WlanConnect(
			hClient,
			&guidIntf,
			&wlanConnPara,
			NULL            // reserved
			);

	}
	__finally
	{
		// clean up
		if (hClient != NULL)
		{
			WlanCloseHandle(
				hClient, 
				NULL            // reserved
				);
		}
	}

	PrintErrorMsg(argv[0], dwError);
}

// discovery a network without using a saved profile
VOID 
Discover(
		 __in int argc, 
		 __in_ecount(argc) LPWSTR argv[]
)
{
	DWORD dwError = ERROR_SUCCESS;
	HANDLE hClient = NULL;
	GUID guidIntf;
	DOT11_SSID dot11Ssid = {0};
	WLAN_CONNECTION_PARAMETERS wlanConnPara;

	__try
	{
		if (argc != 5)
		{
			dwError = ERROR_INVALID_PARAMETER;
			__leave;
		}

		// get the interface GUID
		if (UuidFromString((RPC_CSTR)argv[1], &guidIntf) != RPC_S_OK)
		{
			wcerr << L"Invalid GUID " << argv[1] << endl;
			dwError = ERROR_INVALID_PARAMETER;
			__leave;
		}

		// get SSID
		if ((dwError = StringWToSsid(argv[2], &dot11Ssid)) != ERROR_SUCCESS)
		{
			__leave;
		}

		// profile is ignored for discovery
		wlanConnPara.strProfile = NULL;
		// set the SSID
		wlanConnPara.pDot11Ssid = &dot11Ssid;

		// get BSS type
		if (_wcsicmp(argv[3],L"adhoc") == 0 || _wcsicmp(argv[3], L"a") == 0)
			wlanConnPara.dot11BssType = dot11_BSS_type_independent;
		else if (_wcsicmp(argv[3], L"infrastructure") == 0 || _wcsicmp(argv[3], L"i") == 0)
			wlanConnPara.dot11BssType = dot11_BSS_type_infrastructure;
		else
		{
			dwError = ERROR_INVALID_PARAMETER;
			__leave;
		}

		// get whether security enabled or not
		if (_wcsicmp(argv[4], L"secure") == 0 || _wcsicmp(argv[4], L"s") == 0)
			wlanConnPara.wlanConnectionMode = wlan_connection_mode_discovery_secure;
		else if (_wcsicmp(argv[4], L"unsecure") == 0 || _wcsicmp(argv[4], L"u") == 0)
			wlanConnPara.wlanConnectionMode = wlan_connection_mode_discovery_unsecure;
		else
		{
			dwError = ERROR_INVALID_PARAMETER;
			__leave;
		}

		// the desired BSSID list is empty
		wlanConnPara.pDesiredBssidList = NULL;
		// no connection flags
		wlanConnPara.dwFlags = 0;

		// open handle
		if ((dwError = OpenHandleAndCheckVersion(
			&hClient
			)) != ERROR_SUCCESS)
		{
			__leave;
		}


		dwError = WlanConnect(
			hClient,
			&guidIntf,
			&wlanConnPara,
			NULL            // reserved
			);

	}
	__finally
	{
		// clean up
		if (hClient != NULL)
		{
			WlanCloseHandle(
				hClient, 
				NULL            // reserved
				);
		}
	}

	PrintErrorMsg(argv[0], dwError);
}

// disconnect from the current network
VOID 
Disconnect(
		   __in int argc, 
		   __in_ecount(argc) LPWSTR argv[]
)
{
	DWORD dwError = ERROR_SUCCESS;
	HANDLE hClient = NULL;
	GUID guidIntf;

	__try
	{
		if (argc != 2)
		{
			dwError = ERROR_INVALID_PARAMETER;
			__leave;
		}

		// get the interface GUID
		if (UuidFromString((RPC_CSTR)argv[1], &guidIntf) != RPC_S_OK)
		{
			wcerr << L"Invalid GUID " << argv[1] << endl;
			dwError = ERROR_INVALID_PARAMETER;
			__leave;
		}

		// open handle
		if ((dwError = OpenHandleAndCheckVersion(
			&hClient
			)) != ERROR_SUCCESS)
		{
			__leave;
		}

		dwError = WlanDisconnect(
			hClient, 
			&guidIntf, 
			NULL            // reserved
			);

	}
	__finally
	{
		// clean up
		if (hClient != NULL)
		{
			WlanCloseHandle(
				hClient, 
				NULL            // reserved
				);
		}
	}

	PrintErrorMsg(argv[0], dwError);
}

// save a temporary profile
// a temporary profile can be generated by the service for discovery
// or passed with WlanConnect when the connection mode is wlan_connection_mode_temporary_profile
VOID 
SaveTemporaryProfile(
					 __in int argc, 
					 __in_ecount(argc) LPWSTR argv[]
)
{
	DWORD dwError = ERROR_SUCCESS;
	HANDLE hClient = NULL;
	GUID guidIntf;
	DWORD dwFlags = 0;

	__try
	{
		if (argc != 3)
		{
			dwError = ERROR_INVALID_PARAMETER;
			__leave;
		}

		// get the interface GUID
		if (UuidFromString((RPC_CSTR)argv[1], &guidIntf) != RPC_S_OK)
		{
			wcerr << L"Invalid GUID " << argv[1] << endl;
			dwError = ERROR_INVALID_PARAMETER;
			__leave;
		}

		// open handle
		if ((dwError = OpenHandleAndCheckVersion(
			&hClient
			)) != ERROR_SUCCESS)
		{
			__leave;
		}

		dwError = WlanSaveTemporaryProfile(
			hClient, 
			&guidIntf, 
			argv[2],        // profile name
			NULL,           // use default ACL
			0,              // no profile flags 
			TRUE,           // overwrite the existing profile
			NULL            // reserved
			);

	}
	__finally
	{
		// clean up
		if (hClient != NULL)
		{
			WlanCloseHandle(
				hClient, 
				NULL            // reserved
				);
		}
	}
	PrintErrorMsg(argv[0], dwError);
}

// show help messages
VOID 
Help(
	 __in int argc, 
	 __in_ecount(argc) LPWSTR argv[]
);

typedef VOID (*WLSAMPLE_FUNCTION) (int argc, LPWSTR argv[]);

typedef struct _WLSAMPLE_COMMAND {
	LPWSTR strCommandName;           // command name
	LPWSTR strShortHand;             // a shorthand for the command
	WLSAMPLE_FUNCTION Func;         // pointer to the function
	LPWSTR strHelpMessage;          // help message
	LPWSTR strParameters;           // parameters for the command
	BOOL bRemarks;                  // whether have remarks for the command
	LPWSTR strRemarks;              // remarks
} WLSAMPLE_COMMAND, *PWLSAMPLE_COMMAND;

WLSAMPLE_COMMAND g_Commands[] = {
	// interface related commands
	{
		L"EnumInterface",
			L"ei",
			EnumInterface,
			L"Enumerate wireless interfaces and print the basic interface information.",
			L"",
			FALSE,
			L""
	},
	{
		L"GetInterfaceCapability",
			L"gic",
			GetInterfaceCapability,
			L"Get the capability of an interface.",
			L"<interface GUID>",
			TRUE,
			L"Use EnumInterface (ei) command to get the GUID of an interface."
		},
		{
			L"QueryInterface",
				L"qi",
				QueryInterface,
				L"Query the basic information of an interface.",
				L"<interface GUID>",
				TRUE,
				L"Use EnumInterface (ei) command to get the GUID of an interface."
		},
		{
			L"SetRadioState",
				L"srs",
				SetRadioState,
				L"Set the software radio state.",
				L"<interface GUID> <on|off>",
				TRUE,
				L"Use EnumInterface (ei) command to get the GUID of an interface."
			},
			{
				L"GetDriverStatistics",
					L"gds",
					GetDriverStatistics,
					L"Get driver statistics." ,
					L"<interface GUID>",
					TRUE,
					L"Use EnumInterface (ei) command to get the GUID of an interface."
			},
			// scan related commands
			{
				L"Scan",
					L"scan",
					Scan,
					L"Scan for available wireless networks.",
					L"<interface GUID>",
					TRUE,
					L"Use EnumInterface (ei) command to get the GUID of an interface."
				},
				{
					L"GetBssList",
						L"gbs",
						GetBssList,
						L"Get the list of BSS." ,
						L"<interface GUID> [<SSID> <infrastructure(i)|adhoc(a)> <secure(s)|unsecure(u)>]",
						TRUE,
						L"Use EnumInterface (ei) command to get the GUID of an interface."
				},
				{
					L"GetVisibleNetworkList",
						L"gvl",
						GetVisibleNetworkList,
						L"Get the list of visible wireless networks.",
						L"<interface GUID>",
						TRUE,
						L"Use EnumInterface (ei) command to get the GUID of an interface."
					},
					// profile releated commands
					{
						L"SetProfile",
							L"sp",
							SetProfile,
							L"Save a profile.",
							L"<interface GUID> <profile XML file name>",
							TRUE,
							L"Use EnumInterface (ei) command to get the GUID of an interface."
					},
					{
						L"SaveTempProfile",
							L"stp",
							SaveTemporaryProfile,
							L"Save the temporary profile used for the current connection.",
							L"<interface GUID> <profile name>",
							TRUE,
							L"Use EnumInterface (ei) command to get the GUID of an interface."
						},
						{
							L"GetProfile",
								L"gp",
								SetProfile,
								L"Get the content of a saved profile.",
								L"<interface GUID> <profile name>",
								TRUE,
								L"Use EnumInterface (ei) command to get the GUID of an interface."
						},
						{
							L"DeleteProfile",
								L"dp",
								DeleteProfile,
								L"Delete a saved profile.",
								L"<interface GUID> <profile name>",
								TRUE,
								L"Use EnumInterface (ei) command to get the GUID of an interface."
							},
							{
								L"SetProfileList",
									L"spl",
									SetProfileList,
									L"Set the preference order of saved profiles. The list must contain all profiles.",
									L"<interface GUID> <profile name>+",
									TRUE,
									L"Use EnumInterface (ei) command to get the GUID of an interface."
							},
							{
								L"GetProfileList",
									L"gpl",
									GetProfileList,
									L"Get the list of saved profiles, in the preference order." ,
									L"<interface GUID>",
									TRUE,
									L"Use EnumInterface (ei) command to get the GUID of an interface."
								},
								// connection related commands
								{
									L"Connect",
										L"conn",
										Connect,
										L"Connect to a wireless network using a saved profile.",
										L"<interface GUID> <SSID> <infrastructure(i)|adhoc(a)> <profile name>",
										TRUE,
										L"Use EnumInterface (ei) command to get the GUID of an interface."
								},
								{
									L"Disconnect",
										L"dc",
										Disconnect,
										L"Disconnect from the current network.",
										L"<interface GUID>",
										TRUE,
										L"Use EnumInterface (ei) command to get the GUID of an interface."
									},
									{
										L"Discover",
											L"disc",
											Discover,
											L"Connect to a network without a saved profile. The WLAN service will discover the settings for connection.",
											L"<interface GUID> <SSID> <infrastructure(i)|adhoc(a)> <secure(s)|unsecure(u)>",
											TRUE,
											L"Use EnumInterface (ei) command to get the GUID of an interface."
									},
									// other commands
									{
										L"RegisterNotif",
											L"r",
											RegisterNotification,
											L"Register ACM and MSM notifications.",
											L"",
											FALSE,
											L""
										},
										{
											L"help",
												L"?",
												Help,
												L"Print this help message.",
												L"[<command>]",
												FALSE,
												L""
										}
};

// show help messages
VOID 
Help(
	 __in int argc, 
	 __in_ecount(argc) LPWSTR argv[]
)
{
	UINT i;

	if (argc == 1)
	{
		// show all commands
		wcout << L"This is a sample showing how to use WLAN APIs to manager wireless networks." << endl;
		wcout << L"The following commands are available. Use \"help xyz\" to show the description of command xyz." << endl;
		for (i=0; i < sizeof(g_Commands)/sizeof(WLSAMPLE_COMMAND); i++)
		{
			wcout << L"\t"<< g_Commands[i].strCommandName;
			wcout << L"(" << g_Commands[i].strShortHand << L")" << endl;
		}
	}
	else if (argc == 2)
	{
		// show the description of a command
		for (i=0; i < sizeof(g_Commands)/sizeof(WLSAMPLE_COMMAND); i++)
		{
			if (_wcsicmp(argv[1], g_Commands[i].strCommandName) == 0 ||
				_wcsicmp(argv[1], g_Commands[i].strShortHand) == 0)
			{
				wcout << L"Command: " << g_Commands[i].strCommandName;
				wcout << L"(" << g_Commands[i].strShortHand << L")" << endl;
				wcout << L"Description: " << g_Commands[i].strHelpMessage << endl;
				wcout << L"Usage: " << g_Commands[i].strCommandName;
				wcout << L"(" << g_Commands[i].strShortHand << L") ";
				wcout << g_Commands[i].strParameters << endl;
				if (g_Commands[i].bRemarks)
				{
					wcout << L"Remarks: " << g_Commands[i].strRemarks << endl;
				}
				break;
			}
		}
	}
	else
	{
		PrintErrorMsg(argv[0], ERROR_INVALID_PARAMETER);
	}
}

// command is stored in the global variable
void 
ExecuteCommand(
			   __in int argc, 
			   __in_ecount(argc) LPWSTR argv[]
)
{
	UINT i = 0;

	for (i=0; i < sizeof(g_Commands)/sizeof(WLSAMPLE_COMMAND); i++)
	{
		// find the command and call the function
		if (_wcsicmp(argv[0], g_Commands[i].strCommandName) == 0 ||
			_wcsicmp(argv[0], g_Commands[i].strShortHand) == 0)
		{
			g_Commands[i].Func(argc, argv);
			break;
		}
	}

	if (i == sizeof(g_Commands)/sizeof(WLSAMPLE_COMMAND))
	{
		wcerr << L"Invalid command " << argv[0] << L"!" << endl;
	}
}

//// the main program
//int _cdecl 
//wmain(
//	  __in int argc, 
//	  __in_ecount(argc) LPWSTR argv[]
//)
//{
//	DWORD dwRetCode = ERROR_SUCCESS;
//
//	if (argc <= 1)
//	{
//		wcout << L"Please type \"" << argv[0] << L" ?\" for help." << endl;
//		dwRetCode = ERROR_INVALID_PARAMETER;
//	}
//	else
//	{
//		// don't pass in the first parameter
//		ExecuteCommand(argc-1, argv+1);
//	}
//
//	return dwRetCode;
//}
//
